package com.xlh.service.courseTest.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.google.common.base.Objects;
import com.google.common.collect.*;
import com.xlh.dao.courseTest.AnswerSheetReportMapperExt;
import com.xlh.dao.courseTest.CourseTestPaperAnswerSheetMapper;
import com.xlh.dao.courseTest.CourseTestPaperAnswerSheetMapperExt;
import com.xlh.dto.course.CourseBasicDTO;
import com.xlh.dto.course.StatisticsDTO;
import com.xlh.dto.courseTest.*;
import com.xlh.dto.courseTest.practice.PracticeClassDTO;
import com.xlh.dto.user.ClassCourseDTO;
import com.xlh.dto.user.UserInfoDTO;
import com.xlh.enums.courseTest.AnswerSheetStatusEnum;
import com.xlh.enums.courseTest.PaperStatusEnum;
import com.xlh.enums.courseTest.QuestionTypeEnum;
import com.xlh.enums.courseTest.StudentStatusEnum;
import com.xlh.exception.common.GlobalException;
import com.xlh.pojo.courseTest.*;
import com.xlh.pojo.user.Class;
import com.xlh.service.course.CourseService;
import com.xlh.service.courseTest.*;
import com.xlh.service.user.ClassService;
import com.xlh.service.user.UserService;
import com.xlh.util.BeanUtil;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

/**
 * @author zhr 2019/3/2
 */
@Service
@DependsOn({"springContextUtil"})
public class PaperAnswerSheetServiceImpl implements PaperAnswerSheetService {

    private static Logger logger = LoggerFactory.getLogger(PaperAnswerSheetServiceImpl.class);

    @Autowired
    private PaperQuestionService questionService;
    @Autowired
    private PaperService paperService;
    @Autowired
    private PaperAnswerService answerService;
    @Autowired
    private ExperimentService experimentService;
    @Autowired
    private ClassService classService;
    @Autowired
    private CourseService courseService;
    @Autowired
    private UserService userService;

    @Autowired
    private CourseTestPaperAnswerSheetMapper mapper;

    @Autowired
    private CourseTestPaperAnswerSheetMapperExt mapperExt;

    @Autowired
    private AnswerSheetReportMapperExt answerSheetReportMapperExt;

    /**
     * 考试过程中的全局缓存,手动控制清除
     * Table<paperId, answerSheetId, answers>
     **/
    private static Table<Long, Long, List<AnswerSheetDTO>> answerSheetTable = Tables.synchronizedTable(HashBasedTable.create());

    @Override
    public void insertNewAnswerSheet(Long paperId, List<Long> studentIds) {
        if (CollectionUtils.isEmpty(studentIds)) {
            throw new GlobalException("该班级下没有学生");
        }

        // 获取答题卡封装集
        List<AnswerSheetTypeDTO> answerSheetList = getPaperAnswerSheet(paperId);
        List<CourseTestPaperAnswerSheet> list = Lists.newArrayList();

        // 封装insert对象集
        Long maxId = mapperExt.selectMaxId();
        if (maxId == null) {
            maxId = 0L;
        }
        for (Long studentId : studentIds) {
            CourseTestPaperAnswerSheet answerSheet = new CourseTestPaperAnswerSheet(paperId, studentId);
            answerSheet.setId(++maxId);
            answerSheet.setContent(JSONArray.toJSONString(answerSheetList));
            list.add(answerSheet);
        }

        // 批量insert
        mapperExt.insertBatch(list);
    }

    private List<AnswerSheetTypeDTO> getPaperAnswerSheet(Long paperId) {
        List<AnswerSheetDTO> answerSheetList = Lists.newArrayList();

        // 查询试卷下所有试题
        List<CourseTestPaperQuestion> questionList = questionService.selectByPaperId(paperId);
        // 生成AnswerSheet题目对象并插入至result中
        questionList.forEach(question -> answerSheetList.add(
                new AnswerSheetDTO(question.getId(), question.getOrderNumber(), question.getType()))
        );

        // 转化AnswerSheetDTO为AnswerSheetTypeDTO
        return AnswerSheetTypeDTO.transform(answerSheetList);
    }

    @Override
    public CourseTestPaperAnswerSheet selectByPrimaryKey(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public List<CourseTestPaperAnswerSheet> selectByPrimaryKeys(List<Long> answerSheetListIds) {

        CourseTestPaperAnswerSheetExample example = new CourseTestPaperAnswerSheetExample();
        example.createCriteria().andIdIn(answerSheetListIds);
        List<CourseTestPaperAnswerSheet> courseTestPaperAnswerSheets = mapper.selectByExample(example);

        return courseTestPaperAnswerSheets;
    }


    @Override
    public void updateAnswerSheet(CourseTestPaperAnswerSheet answerSheet) {
        mapper.updateByPrimaryKeySelective(answerSheet);
    }

    @Override
    public List<AnswerSheetListDTO> selectStudentList(String userInfo, Long paperId) {
        return mapperExt.selectStudentList(userInfo, paperId);
    }

    @Override
    public CourseTestPaperAnswerSheet selectByPaperIdAndStudentId(Long paperId, Long userId) {
        return mapperExt.selectByPaperIdAndStudentId(paperId, userId);
    }

    @Override
    public boolean allChecked(Long paperId) {
        CourseTestPaperAnswerSheetExample example = new CourseTestPaperAnswerSheetExample();
        example.createCriteria().andPaperIdEqualTo(paperId)
                .andPaperStatusEqualTo(PaperStatusEnum.READING.getCode()).andDelMarkEqualTo(false);
        return mapper.countByExample(example) == 0;
    }

    @Override
    public List<CourseTestPaperAnswerSheet> selectEndedPaperByPaperId(Long paperId) {
        // 获取交卷状态的数据
        List<CourseTestPaperAnswerSheet> submitList = selectByPaperIdPaperStat(paperId, StudentStatusEnum.SUBMITTED);
        // 获取已批阅状态的数据
        List<CourseTestPaperAnswerSheet> endList = selectByPaperIdPaperStat(paperId, StudentStatusEnum.ENDED);

        // 合并两组数据并重新排序
        List<CourseTestPaperAnswerSheet> list = Lists.newArrayList();
        list.addAll(submitList);
        list.addAll(endList);
        list.sort(Comparator.comparingLong(CourseTestPaperAnswerSheet::getId));

        return list;
    }

    private List<CourseTestPaperAnswerSheet> selectByPaperIdPaperStat(Long paperId, StudentStatusEnum studentStat) {
        CourseTestPaperAnswerSheetExample example = new CourseTestPaperAnswerSheetExample();
        example.createCriteria().andPaperIdEqualTo(paperId).andDelMarkEqualTo(false).andPaperStatusEqualTo(studentStat.getStatus());
        List<CourseTestPaperAnswerSheet> list = mapper.selectByExampleWithBLOBs(example);
        return CollectionUtils.isEmpty(list) ? Lists.newArrayList() : list;
    }

    @Override
    public void cleanData() {
        mapperExt.cleanData();
    }

    @Override
    public void put(Long paperId, Long answerSheetId, List<AnswerSheetDTO> answerSheetList) {
        answerSheetTable.put(paperId, answerSheetId, answerSheetList);
    }

    @Override
    public List<AnswerSheetDTO> get(Long paperId, Long answerSheetId) {
        return answerSheetTable.get(paperId, answerSheetId);
    }

    @Override
    public void remove(Long paperId, Long answerSheetId) {
        answerSheetTable.remove(paperId, answerSheetId);
    }

    @Override
    public void clearCache() {
        answerSheetTable.clear();
    }

    @Override
    public CourseTestPaperAnswerSheet getAnswerSheet(Long id) {
        return selectByPrimaryKey(id);
    }

    @Override
    public List<PaperAnswerSheetDTO> selectByCourseIdPaperStat(Long courseId, Integer stat) {
        return mapperExt.selectByCourseIdWithoutBLOBs(courseId, stat);
    }

    @Override
    public boolean isTesting(List<Long> userIds, Long courseId) {
        return mapperExt.countByUserIdsCourseId(userIds, courseId) > 0;
    }

    @Override
    public boolean isTestings(List<Long> userIds, List<Long> courseIds) {
        return mapperExt.countByUserIdsCourseIds(userIds, courseIds) > 0;
    }

    @Override
    public StatisticsDTO getClassCheckCount(List<Long> classIds, Long courseId) {
        List<ClassCheckCountDTO> list = mapperExt.getClassCheckCount(classIds, courseId);
        return ClassCheckCountDTO.convert2StatisticsDTO(list);
    }

    @Override
    public StatisticsDTO getClassCheckCountOther(List<Long> classIds, Long courseId) {
        List<ClassCheckCountDTO> list = mapperExt.getClassCheckCountOther(classIds, courseId);
        return ClassCheckCountDTO.convert2StatisticsDTONew(list);
    }

    @Override
    public CourseTestPaperAnswerSheet insertAndReturn(Long userId, Long paperId) {
        List<AnswerSheetTypeDTO> answerSheetList = getPaperAnswerSheet(paperId);

        CourseTestPaperAnswerSheet answerSheet = new CourseTestPaperAnswerSheet(paperId, userId);
        answerSheet.setContent(JSONArray.toJSONString(answerSheetList));
        mapper.insertSelective(answerSheet);
        return selectByPrimaryKey(answerSheet.getId());
    }

    @Override
    public CourseTestPaperAnswerSheet selectInsert(Long userId, Long paperId) {
        CourseTestPaperAnswerSheet answerSheet = selectByPaperIdAndStudentId(paperId, userId);
        if (answerSheet == null) {
            answerSheet = insertAndReturn(userId, paperId);
        }

        return answerSheet;
    }

    @Override
    public void save(Long answerSheetId, List<AnswerSheetTypeDTO> answerSheetTypeList, Long paperId) {
        List<AnswerSheetDTO> answerSheetList = AnswerSheetDTO.parse(answerSheetTypeList);
        put(paperId, answerSheetId, answerSheetList);
    }

    @Override
    public Integer submitBase(Long answerSheetId, List<AnswerSheetTypeDTO> answerSheetTypeList, Long paperId) {
        CourseTestPaperAnswerSheet answerSheet = getAnswerSheet(answerSheetId);

        AnswerSheetStatusEnum statusEnum = answerSheetTypeList.stream().anyMatch(
                dto -> Objects.equal(dto.getType(), QuestionTypeEnum.EXPERIMENT.getCode())
        ) ? AnswerSheetStatusEnum.EXPERIMENT_TEST : AnswerSheetStatusEnum.READING;

        setUpdate(answerSheet, answerSheetTypeList, statusEnum);

        put(paperId, answerSheetId, AnswerSheetDTO.parse(answerSheetTypeList));

        return statusEnum.getStatus();
    }

    @Override
    public void submitExperiment(Long answerSheetId, Long paperId) {
        CourseTestPaperAnswerSheet answerSheet = getAnswerSheet(answerSheetId);

        setUpdate(answerSheet, null, AnswerSheetStatusEnum.READING);

        // 修改实验报告的状态
        experimentService.updateTestCommit(answerSheetId);
    }

    @Override
    public void setUpdate(
            CourseTestPaperAnswerSheet answerSheet,
            List<AnswerSheetTypeDTO> answerSheetTypeList,
            AnswerSheetStatusEnum statusEnum
    ) {
        if (CollectionUtils.isNotEmpty(answerSheetTypeList)) {
            answerSheet.setContent(JSONArray.toJSONString(answerSheetTypeList));
        }
        answerSheet.setPaperStatus(statusEnum.getStatus());
        answerSheet.setUpdateTime(DateTime.now());
        updateAnswerSheet(answerSheet);
    }

    @Override
    public void saveCache() {
        List<CourseTestPaperAnswerSheet> answerSheetList = getAnswerSheetCache();

        if (CollectionUtils.isNotEmpty(answerSheetList)) {
            mapperExt.updateSelectiveBatch(answerSheetList);
        }
    }

    @Override
    public void endTest(Long paperId) {
        // 已经答题的学生将缓存中的数据全部保存下来
        List<CourseTestPaperAnswerSheet> baseList = Lists.newArrayList();
        Map<Long, List<AnswerSheetDTO>> idAnswerMap = answerSheetTable.row(paperId);
        List<Long> answerSheetIds = Lists.newArrayList(idAnswerMap.keySet());

        try {
            idAnswerMap.forEach((id, answers) ->
                    baseList.add(new CourseTestPaperAnswerSheet(
                            id,
                            CollectionUtils.isNotEmpty(answers) ? JSONArray.toJSONString(AnswerSheetTypeDTO.transform(answers)) : null,
                            AnswerSheetStatusEnum.READING.getStatus()
                    ))
            );
            answerSheetIds.forEach(id -> remove(paperId, id));
        } catch (Exception e) {
            logger.error("", e);
        }

        // 批阅客观题
        List<CourseTestPaperAnswerSheet> checkedList = objectiveCheck(baseList, paperId);

        // 实验题的学生答题情况
        List<CourseTestPaperAnswerSheet> experimentList = selectExperiment(paperId);


        List<Long> baseIds = baseList.stream().map(CourseTestPaperAnswerSheet::getId).collect(Collectors.toList());
        List<Long> experimentIds = experimentList.stream().map(CourseTestPaperAnswerSheet::getId).collect(Collectors.toList());

        // 实验题提交情况更新
        updateExperiment(experimentIds);

        // 缺考的学生自动变为已批阅
        List<CourseTestPaperAnswerSheet> absentList = absentList(paperId, baseIds, experimentIds);

        if (CollectionUtils.isNotEmpty(absentList)) {
            absentList.forEach(answerSheet -> {
                answerSheet.setPaperStatus(PaperStatusEnum.READ.getCode());
                answerSheet.setUpdateTime(DateTime.now());
                answerSheet.setScore(0);
                checkedList.add(answerSheet);
            });
        }

        if (CollectionUtils.isNotEmpty(checkedList)) {
            mapperExt.updateSelectiveBatch(checkedList);
        }
    }

    /**
     * 更新实验题的实验报告提交状态
     * @param answerSheetIds
     */
    private void updateExperiment(List<Long> answerSheetIds) {
        if(CollectionUtils.isEmpty(answerSheetIds)) {
            return;
        }

        List<ExperimentReport> reportList = experimentService.selectByAnswerSheetIds(answerSheetIds);

        reportList.forEach(report -> {
            if (report.getReportMd() != null) {
                report.setOnlineCommit(true);
                report.setUpdateTime(DateTime.now());
                experimentService.updateByPrimaryKey(report);
            }
        });
    }

    private List<CourseTestPaperAnswerSheet> absentList(Long paperId, List<Long> baseIds, List<Long> experimentIds) {
        CourseTestPaperAnswerSheetExample example = new CourseTestPaperAnswerSheetExample();
        CourseTestPaperAnswerSheetExample.Criteria criteria = example.createCriteria();
        criteria.andPaperIdEqualTo(paperId).andDelMarkEqualTo(false);
        if (CollectionUtils.isNotEmpty(baseIds)) {
            criteria.andIdNotIn(baseIds);
        }
        if (CollectionUtils.isNotEmpty(experimentIds)) {
            criteria.andIdNotIn(experimentIds);
        }
        return mapper.selectByExampleWithBLOBs(example);
    }

    private List<CourseTestPaperAnswerSheet> objectiveCheck(List<CourseTestPaperAnswerSheet> answerSheetList, Long paperId) {
        List<CourseTestPaperQuestion> questionList = questionService.selectByPaperId(paperId);
        Map<Long, CourseTestPaperQuestion> idQuestionMap = BeanUtil.mapByKey("id", questionList);

        List<Long> questionIds = questionList.stream().map(CourseTestPaperQuestion::getId).collect(Collectors.toList());
        List<CourseTestPaperAnswer> answerList = answerService.selectAnswerList(questionIds, paperId);
        Map<Long, List<CourseTestPaperAnswer>> questionIdAnswerListMap = BeanUtil.aggByKeyToList("questionId", answerList);

        // 提取答题卡详情并批阅
        for (CourseTestPaperAnswerSheet answerSheet : answerSheetList) {
            List<AnswerSheetDTO> answerSheetDTOList = AnswerSheetDTO.parse(answerSheet.getContent());
            if (CollectionUtils.isEmpty(answerSheetDTOList)) {
                continue;
            }
            answerSheetDTOList.forEach(dto -> {
                QuestionTypeEnum typeEnum = QuestionTypeEnum.forCode(dto.getType());
                if (typeEnum == null) {
                    throw new GlobalException("无法识别题型");
                }

                try {
                    typeEnum.checkPaper(dto, questionIdAnswerListMap.get(dto.getId()), idQuestionMap.get(dto.getId()));
                } catch (UnsupportedOperationException e) {
                    logger.info("主观题,已跳过自动批阅");
                } catch (Exception e) {
                    throw new GlobalException("自动批阅异常");
                }
            });

            answerSheet.setScore(answerSheetDTOList.stream().map(AnswerSheetDTO::getScore).reduce(0, Integer::sum));
            answerSheet.setContent(JSONArray.toJSONString(AnswerSheetTypeDTO.transform(answerSheetDTOList)));
            answerSheet.setUpdateTime(DateTime.now());
        }

        return answerSheetList;
    }

    private List<CourseTestPaperAnswerSheet> selectExperiment(Long paperId) {
        List<CourseTestPaperAnswerSheet> result = mapperExt.selectExperiment(paperId);
        return CollectionUtils.isEmpty(result) ? Lists.newArrayList() : result;
    }

    @Override
    public List<CourseTestPaper> listStudentExam(Long courseId, Long userId) {
        return mapperExt.listStudentExam(courseId, userId, PaperStatusEnum.READ.getCode());
    }

    @Override
    public List<Long> getTestingCourse(List<Long> classIds) {
        if (CollectionUtils.isEmpty(classIds)) {
            return Lists.newArrayList();
        }
        return mapperExt.getTestingCourse(classIds);
    }

    @Override
    public void deleteByPaperId(Long paperId) {
        CourseTestPaperAnswerSheetExample example = new CourseTestPaperAnswerSheetExample();
        example.createCriteria().andPaperIdEqualTo(paperId);
        mapper.deleteByExample(example);
    }

    @Override
    public StatisticsDTO getClassCheckCount(Map<Long, List<ClassCourseDTO>> courseIdClassIdsMap) {
        // TODO 重写接口实现
        if (courseIdClassIdsMap == null) {
            return new StatisticsDTO();
        }

        // 通过课程id获取一个较大的数据集合
        List<Long> courseIdList = Lists.newArrayList(courseIdClassIdsMap.keySet());
        List<ClassCheckCountDTO> list = mapperExt.selectUncheckedByCourseIds(courseIdList);
        if (CollectionUtils.isEmpty(list)) {
            return new StatisticsDTO();
        }

        // 获取班级-学生映射关系
        Map<Long, List<Long>> classIdStudentIdsMap = getClassIdStudentIdsMap(courseIdClassIdsMap.values());
        Map<Long, Map<Long, List<Long>>> courseClassStudentsMap = getCourseClassStudentsMap(courseIdClassIdsMap, classIdStudentIdsMap);
        list.forEach(dto -> courseClassStudentsMap.forEach((courseId, classStudentMap) -> {
            if (java.util.Objects.equals(dto.getCourseId(), courseId)) {
                classStudentMap.forEach((classId, students) -> {
                    if (students.contains(dto.getStudentId())) {
                        dto.setId(classId);
                    }
                });
            }
        }));

        // 整合每个班级
        Map<Long, Long> classIdUncheckedCountMap = Maps.newHashMap();
        List<PracticeClassDTO> courseClassNameList = Lists.newArrayList();
        courseIdClassIdsMap.forEach((courseId, classes) -> {
            for (ClassCourseDTO clazz : classes) {
                long count = list.stream().filter(dto -> java.util.Objects.equals(dto.getCourseId(), courseId) && java.util.Objects.equals(dto.getId(), clazz.getId())).count();
                classIdUncheckedCountMap.merge(clazz.getId(), count, Long::sum);

                if (count != 0L) {
                    PracticeClassDTO dto = new PracticeClassDTO();
                    dto.setCourseId(courseId);
                    dto.setClassId(clazz.getId());
                    dto.setGrade(clazz.getGrade());
                    dto.setIs_ended(clazz.getEnded().toString());
                    courseClassNameList.add(dto);
                }
            }
        });

        convertToName(courseClassNameList);

        Long total = classIdUncheckedCountMap.values().stream().mapToLong(Long::longValue).sum();

        return new StatisticsDTO(total, null, courseClassNameList);
    }

    @Override
    public List<UserCourseTestInfoDTO> findTestStatisticsByUserIds(Long courseId, Long classId, List<Long> userIds) {

        CopyOnWriteArrayList<UserCourseTestInfoDTO> allTempUsers = Lists.newCopyOnWriteArrayList();
        List<UserCourseTestInfoDTO> userTestInfos = mapperExt.findTestStatsticsByUserIds(courseId, classId, userIds, null);
        // 按照paperID 进行数据的补充
        Map<Long, List<UserCourseTestInfoDTO>> userTestInfosMap = userTestInfos.stream().collect(Collectors.groupingBy(UserCourseTestInfoDTO::getId));
        Set<Long> paperKeys = userTestInfosMap.keySet();
        // 查询结果的所有数据的空对象
        for (Long userId : userIds) {
            for (Long paperKey : paperKeys) {
                UserCourseTestInfoDTO userCourseTestInfoDTO = new UserCourseTestInfoDTO();
                userCourseTestInfoDTO.setId(paperKey);
                userCourseTestInfoDTO.setCourseId(courseId);
                userCourseTestInfoDTO.setClassId(classId);
                userCourseTestInfoDTO.setUserId(userId);
                allTempUsers.add(userCourseTestInfoDTO);
            }
        }
        // 用查出来的数据覆盖模板中数据
        for (UserCourseTestInfoDTO allTempUser : allTempUsers) {
            for (UserCourseTestInfoDTO userTestInfo : userTestInfos) {
                if(allTempUser.getUserId().equals(userTestInfo.getUserId())&&
                        allTempUser.getId().equals(userTestInfo.getId())){
                    allTempUsers.remove(allTempUser);
                    allTempUsers.add(userTestInfo);
                }
            }
        }
        Console.log(allTempUsers);
        return allTempUsers;
    }

    @Override
    public List<AnswerSheetExprimentInfoDTO> getExperimentInfo(Long paperId) {

        List<AnswerSheetExprimentInfoDTO> answerSheetExprimentInfoDTOS = answerSheetReportMapperExt.getExperimentInfo(paperId);

        return answerSheetExprimentInfoDTOS;
    }




    private Map<Long, Map<Long, List<Long>>> getCourseClassStudentsMap(Map<Long, List<ClassCourseDTO>> courseIdClassIdsMap, Map<Long, List<Long>> classIdStudentIdsMap) {
        Map<Long, Map<Long, List<Long>>> result = Maps.newHashMap();
        courseIdClassIdsMap.forEach((courseId, classes) -> {
            Map<Long, List<Long>> classIdStudentsInCourseMap = Maps.newHashMap();
            for (ClassCourseDTO clazz : classes) {
                if (classIdStudentIdsMap.get(clazz.getId()) != null) {
                    classIdStudentsInCourseMap.put(clazz.getId(), classIdStudentIdsMap.get(clazz.getId()));
                }
            }
            result.put(courseId, classIdStudentsInCourseMap);
        });
        return result;
    }

    private void convertToName(List<PracticeClassDTO> list) {
        List<CourseBasicDTO> courseList = courseService.listCourse(list.stream().map(PracticeClassDTO::getCourseId).collect(Collectors.toList()), null , null , null , null , null );
        Map<Long, CourseBasicDTO> courseMap = BeanUtil.mapByKey("id", courseList);
        List<Class> classList = classService.listClass(list.stream().map(PracticeClassDTO::getClassId).collect(Collectors.toList()) , false);
        Map<Long, Class> classMap = BeanUtil.mapByKey("id", classList);

        list.forEach(dto -> {
            dto.setName(courseMap.get(dto.getCourseId()).getName());
            dto.setClassName(classMap.get(dto.getClassId()).getName());
        });
    }

    private Map<Long, List<Long>> getClassIdStudentIdsMap(Collection<List<ClassCourseDTO>> classList) {
        Set<ClassCourseDTO> classSet = Sets.newHashSet();
        for (List<ClassCourseDTO> classes : classList) {
            classSet.addAll(classes);
        }

        List<UserInfoDTO> studentList = userService.queryClassUser(Lists.newArrayList(classSet.stream().map(ClassCourseDTO::getId).collect(Collectors.toList())), null);
        Map<Long, List<UserInfoDTO>> classIdUserListMap = BeanUtil.aggByKeyToList("classId", studentList);

        Map<Long, List<Long>> result = Maps.newHashMap();
        classIdUserListMap.forEach((classId, userList) -> {
            List<Long> userIdList = userList.stream().map(UserInfoDTO::getId).collect(Collectors.toList());
            result.put(classId, userIdList);
        });
        return result;
    }

    private List<CourseTestPaperAnswerSheet> getAnswerSheetCache() {
        List<CourseTestPaperAnswerSheet> result = Lists.newArrayList();
        Map<Long, List<AnswerSheetDTO>> idAnswerMap = Maps.newHashMap();
        // 去除试卷id,化简成Map<Long, List<AnswerSheetDTO>>
        Map<Long, Map<Long, List<AnswerSheetDTO>>> rowMap = answerSheetTable.rowMap();
        rowMap.forEach((paperId, element) -> idAnswerMap.putAll(element));
        idAnswerMap.forEach((id, answers) -> {
            if (CollectionUtils.isNotEmpty(answers)) {
                result.add(
                        new CourseTestPaperAnswerSheet(id, JSONArray.toJSONString(AnswerSheetTypeDTO.transform(answers)), null)
                );
            }
        });
        return result;
    }
}
